package com.cheer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheer.dao.AdminDao;
import com.cheer.dao.ReferenceDao;
import com.cheer.entity.*;
import com.cheer.enums.*;
import com.cheer.exception.ServiceException;
import com.cheer.param.IdsParam;
import com.cheer.param.ReferenceInOrUpParam;
import com.cheer.security.UserInfoHolder;
import com.cheer.service.*;
import com.cheer.vo.ApplicantVO;
import com.cheer.vo.DocumentVO;
import com.cheer.vo.ReferenceDetailVO;
import com.cheer.vo.ReferenceListVO;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


@Service("referenceService")
public class ReferenceServiceImpl extends ServiceImpl<ReferenceDao, ReferenceEntity> implements ReferenceService {


    @Autowired
    private ReferenceFileService referenceFileService;

    @Autowired
    private ApplicantService applicantService;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @Autowired
    private  ReferenceDao referenceDao;

    @Autowired
    private ReferenceReviewLogService referenceReviewLogService;

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private AdminDao adminDao;

    @Autowired
    private ReferencePlacesService referencePlacesService;

    @Autowired
    private ReferencePostService referencePostService;

    @Override
    public void insert(ReferenceInOrUpParam referenceInOrUpParam) {

        Applicant applicant = applicantService.getEntityByAccountId(userInfoHolder.getAccountId());
        // 1. 校验机构ID是否存在
        if(applicant == null){
            throw new ServiceException("未查询到当前集体！");
        }
        ReferenceEntity referenceEntity = new ReferenceEntity();
        referenceEntity.setVintage(DateUtil.format(new Date(), "yyyy"));
        BeanUtil.copyProperties(referenceInOrUpParam, referenceEntity);
        referenceEntity.setAccountId(userInfoHolder.getAccountId());
        referenceEntity.setApplicantId(applicant.getId());
        referenceEntity.setRegisterStatus(RegisterStatusEnum.PROVINCE.getCode());
        save(referenceEntity);
        saveReferenceFile(referenceInOrUpParam, referenceEntity);
    }

    private void saveReferenceFile(ReferenceInOrUpParam referenceInOrUpParam, ReferenceEntity referenceEntity) {
        // 推荐表
        String recommendUrl = referenceInOrUpParam.getRecommend();
        ReferenceFileEntity recommendFileEntity = getReferenceFileEntity(recommendUrl, ReferenceFileEnum.RECOMMEND, referenceEntity.getId());

        // 事迹材料
        String storyUrl = referenceInOrUpParam.getStory();
        ReferenceFileEntity storyUrlEntity = getReferenceFileEntity(storyUrl, ReferenceFileEnum.STORY, referenceEntity.getId());

        // 工作图片
        List<ReferenceFileEntity> list = new ArrayList<>();
        List<String> evidences = referenceInOrUpParam.getEvidences();
        for (int i = 0; i < evidences.size(); i++) {

            String evidenceUrl = evidences.get(i);
            list.add(getReferenceFileEntity(evidenceUrl, ReferenceFileEnum.EVIDENCE, referenceEntity.getId()));
        }
        list.add(recommendFileEntity);
        list.add(storyUrlEntity);
        referenceFileService.batchSave(list, referenceEntity.getId());
    }

    private ReferenceFileEntity getReferenceFileEntity(String recommendUrl, ReferenceFileEnum referenceFileEnum, Long referenceId) {

        ReferenceFileEntity referenceFileEntity = new ReferenceFileEntity();
        referenceFileEntity.setReferenceId(referenceId);
        referenceFileEntity.setFileType(referenceFileEnum.getCode());
        referenceFileEntity.setFileUrl(recommendUrl);
        referenceFileEntity.setAccountId(userInfoHolder.getAccountId());

        return referenceFileEntity;
    }

    @Override
    public void update(ReferenceInOrUpParam referenceInOrUpParam) {

        // 1. 校验机构ID是否存在
        ReferenceEntity referenceEntity = getCurrentYearReferenceEntity();
        if(referenceEntity == null){
            throw new ServiceException("未查询到要修改的集体！");
        }
        Long applicantId = referenceEntity.getApplicantId();
        ApplicantVO byAccountId = applicantService.getByAccountId(applicantId);
        if(byAccountId == null){
            throw new ServiceException("未查询到当前集体！");
        }
        BeanUtil.copyProperties(referenceInOrUpParam, referenceEntity);
        updateById(referenceEntity);
        saveReferenceFile(referenceInOrUpParam, referenceEntity);
    }

    private ReferenceEntity getCurrentYearReferenceEntity() {
        String yyyy = DateUtil.format(new Date(), "yyyy");
        ReferenceEntity referenceEntity = referenceDao.getByCurrentYear(yyyy, userInfoHolder.getAccountId());
        return referenceEntity;
    }

    @Override
    public List<ReferenceListVO> list(Long applicantId) {

        List<ReferenceEntity> referenceEntitys = referenceDao.selectByApplicantId(applicantId);
        List<ReferenceListVO> arrays = new ArrayList<>();
        // 根据
        for (int i = 0; i <referenceEntitys.size(); i++) {

            ReferenceListVO referenceListVO = new ReferenceListVO();
            ReferenceEntity referenceEntity = referenceEntitys.get(i);
            BeanUtil.copyProperties(referenceEntity, referenceListVO, "recommend", "story", "evidences");
            // 资料信息
            referenceFileService.setVO(referenceListVO);
            List<DocumentVO> evidences = referenceListVO.getEvidences();
            if(CollectionUtil.isNotEmpty(evidences)){
                List<String> evidenceLinks = evidences.stream().map(DocumentVO::getLink).collect(Collectors.toList());
                referenceListVO.setEvidenceLinks(evidenceLinks);
                referenceListVO.setRemoveAble(isRemoveAble(referenceEntity));
            }
            arrays.add(referenceListVO);
        }
        return arrays;
    }

    private Boolean isRemoveAble(ReferenceEntity referenceEntity) {
        String vintage = referenceEntity.getVintage();
        if(vintage.equals(DateUtil.format(new Date(), "yyyy"))){
            if(TrueOrFalseEnum.FALSE.getType() == referenceEntity.getIsApply()){
                return true;
            }
        }
        return false;
    }

    @Override
    public ReferenceDetailVO detail() {

        ReferenceEntity currentYearReferenceEntity = getCurrentYearReferenceEntity();
        ReferenceDetailVO referenceDetailVO = getReferenceDetailVO(currentYearReferenceEntity);
        if (referenceDetailVO == null) return null;

        return referenceDetailVO;
    }

    private ReferenceDetailVO getReferenceDetailVO(ReferenceEntity currentYearReferenceEntity) {
        if(currentYearReferenceEntity == null){
            return null;
        }
        ReferenceEntity referenceEntity = referenceDao.selectById(currentYearReferenceEntity.getId());
        if(referenceEntity == null){
            throw new ServiceException("未查询到当前记录");
        }
        ReferenceListVO referenceListVO = new ReferenceListVO();
        BeanUtil.copyProperties(referenceEntity, referenceListVO);
        // 资料信息
        referenceFileService.setVO(referenceListVO);
        ReferenceDetailVO referenceDetailVO = new ReferenceDetailVO();
        BeanUtil.copyProperties(referenceListVO, referenceDetailVO);

        List<DocumentVO> evidences = referenceListVO.getEvidences();
        if(CollectionUtil.isNotEmpty(evidences)){
            List<String> links = evidences.stream().map(DocumentVO::getLink).collect(Collectors.toList());
            referenceDetailVO.setEvidenceLinks(links);
        }else{
            referenceDetailVO.setEvidenceLinks(new ArrayList<>());
        }
        return referenceDetailVO;
    }

    @Override
    public ReferenceDetailVO detail(Long id) {

        ReferenceEntity referenceEntity = getById(id);
        ReferenceDetailVO referenceDetailVO = getReferenceDetailVO(referenceEntity);
        return referenceDetailVO;
    }

    @Override
    public void topOrCancel(IdsParam idsParam) {

        if(CollectionUtil.isEmpty(idsParam.getIds())){
            throw new ServiceException("未查询到选中的记录！");
        }
        List<ReferenceEntity> referenceEntities = listByIds(idsParam.getIds());
        if(CollectionUtil.isEmpty(referenceEntities)){
            return;
        }else{
            referenceEntities.forEach( reference -> {
                Integer isTop = reference.getIsTop();
                if(isTop.equals(TrueOrFalseEnum.TRUE.getType())){
                    reference.setIsTop(TrueOrFalseEnum.FALSE.getType());
                }else{
                    reference.setIsTop(TrueOrFalseEnum.TRUE.getType());
                }
            });
            updateBatchById(referenceEntities);
        }
    }

    @Override
    @Transactional
    public void confer(IdsParam idsParam) {

        if(CollectionUtil.isEmpty(idsParam.getIds())){
            throw new ServiceException("未查询到选中的记录！");
        }
        List<ReferenceEntity> referenceEntities = listByIds(idsParam.getIds());

        for (int i = 0; i < referenceEntities.size(); i++) {

            ReferenceEntity referenceEntity = referenceEntities.get(i);
            if(RegisterStatusEnum.PROVINCE_TITLE.getCode()
                    .equals(referenceEntity.getRegisterStatus())){
                throw new ServiceException("请勿重复授予文明号");
            }
        }

        if(CollectionUtil.isEmpty(referenceEntities)){
            return;
        }else{
            referenceEntities.forEach( reference -> {
                // 获取曾经授予的最高星 + 1
                reference.setIsConfer(TrueOrFalseEnum.TRUE.getType());
                reference.setRegisterStatus(RegisterStatusEnum.PROVINCE_TITLE.getCode());
            });
            updateBatchById(referenceEntities);
            List<Long> applicationIds = referenceEntities.stream().map(ReferenceEntity::getApplicantId).collect(Collectors.toList());
            List<Applicant> applicants = applicantService.listByIds(applicationIds);
            applicants.forEach(applicant -> {

                Integer registerTitle = applicant.getRegisterTitle();
                String titleYear = applicant.getTitleYear();
                if(StrUtil.isEmpty(titleYear)){
                    applicant.setTitleYear(DateUtil.format(new Date(),"yyyy"));
                }
                if( TitleEnum.CITY.getType().equals(registerTitle)){
                    applicant.setTitleYear(DateUtil.format(new Date(),"yyyy"));
                }
                applicant.setRegisterStatus(RegisterStatusEnum.PROVINCE_TITLE.getCode());
                applicant.setRegisterTitle(TitleEnum.PROVINCE.getType());
                applicant.setTitle(TitleEnum.PROVINCE.getType());
                Integer starNum = applicant.getStarNum();
                if(starNum == null){
                    starNum = 0;
                }
                if(starNum < 3){ // 最多授予三颗星
                    starNum = starNum + 1;
                    applicant.setStarNum(starNum);
                }
            });
            applicantService.updateBatchById(applicants);
        }
    }

    @Override
    @Transactional
    public void postTsw(IdsParam idsParam) {

        if(CollectionUtil.isEmpty(idsParam.getIds())){
            throw new ServiceException("未查询到选中的记录！");
        }
        Integer role = userInfoHolder.getAccount().getRole();

        // 下属机构无审批权限
        if(RoleEnum.SECOND_ADMIN.getCode().equals(role) == false){
            return;
        }
        // 获取报送记录
        List<ReferenceEntity> referenceEntities = listByIds(idsParam.getIds());
        List<ReferencePostEntity> records = new ArrayList<>();
        // 总名额
        AtomicReference<Integer> count = new AtomicReference<>(0);
        // 交叉申报名额
        AtomicReference<Integer> cross = new AtomicReference<>(0);
        if(CollectionUtil.isEmpty(referenceEntities)){
            return;
        }else{

            Long adminOrgId = userInfoHolder.getAdminOrgId();
            Organization auditorOrg = organizationService.getById(adminOrgId);
            String auditorOrgPath = auditorOrg.getOrgPath();

            referenceEntities.forEach( reference -> {

                if( TrueOrFalseEnum.TRUE.getType().equals(reference.getIsPost())){
                    throw new ServiceException("存在已经报送集体 请勿重复报送！");
                }
                Integer reviewType = reference.getReviewType();
                if(ReviewTypeEnum.COMMON.getCode().equals(reviewType)){
                    setPostPass(auditorOrgPath, reference);
                    count.set(count.get() + 1);
                }else{ // 行业审批
                    if(reference.getBusiPass().equals(TrueOrFalseEnum.FALSE.getType())){
                        if(reference.getOrgPath().contains(auditorOrgPath)){
                            reference.setBusiPass(TrueOrFalseEnum.TRUE.getType());
                        }else{
                            throw new ServiceException("联合审批需先经过行业系统审批！");
                        }
                    }else{ // 机构审批
                        if (reference.getJoinReviewOrgPath().contains(auditorOrgPath) == false) {
                            throw new ServiceException("当前账号无报送权限！");
                        }
                        reference.setOrgPass(TrueOrFalseEnum.TRUE.getType());
                        reference.setPostOrgId(userInfoHolder.getAdminOrgId());
                        reference.setIsPost(TrueOrFalseEnum.TRUE.getType());
                        cross.set(cross.get() + 1);
                    }
                }
                // 更新日志表
                ReferenceReviewLogEntity log = new ReferenceReviewLogEntity();
                log.setReferenceId(reference.getId());
                log.setReviewType(RegisterStatusEnum.PROVINCE.getCode());
                log.setReviewAdminId(userInfoHolder.getAdminOrgId());
                log.setApplicantId(reference.getApplicantId());
                log.setAction("通过");
                log.setCause("");
                referenceReviewLogService.save(log);

                ReferencePostEntity referencePostEntity = new ReferencePostEntity();
                referencePostEntity.setAccountId(userInfoHolder.getAccountId());
                referencePostEntity.setApplicantId(reference.getApplicantId());
                referencePostEntity.setVintage(DateUtil.format(new Date(), "yyyy"));
                records.add(referencePostEntity);
            });
            updateBatchById(referenceEntities);
            // 查询当前账户剩余
            ReferencePlacesEntity  referencePlaces = referencePlacesService.getByOrgId(userInfoHolder.getAdminOrgId());

            if(referencePlaces == null){
                throw new ServiceException("当前账号未配置报送名额！");
            }
            Integer used = referencePlaces.getUsed() + count.get();
            if( referencePlaces.getCount() <  used){
                throw new ServiceException("已超出当前机构申报名额");
            }
            Integer crossUsed = referencePlaces.getCrossUsed() + cross.get();
            if( referencePlaces.getCross() <  crossUsed){
                throw new ServiceException("已超出本年度交叉申报限额");
            }
            referencePlaces.setUsed(used);
            referencePlaces.setCrossUsed(crossUsed);
            referencePlacesService.updateById(referencePlaces);
            referencePostService.saveBatch(records);
        }
    }

    private void setPostPass(String auditorOrgPath, ReferenceEntity reference) {
        if (reference.getOrgPath().contains(auditorOrgPath) == false) {
            throw new ServiceException("当前账号无报送权限！");
        }
        reference.setOrgPass(TrueOrFalseEnum.TRUE.getType());
        reference.setPostOrgId(userInfoHolder.getAdminOrgId());
        reference.setIsPost(TrueOrFalseEnum.TRUE.getType());
    }

    @Override
    public void deny(Long applicantId, Long accountId, Long adminOrgId, String cause) {

        Integer role = userInfoHolder.getAccount().getRole();


        Applicant applicant = applicantService.getById(applicantId);
        if (applicant == null) {
            throw new ServiceException("集体不存在或已失效");
        }
        Organization organization = organizationService.getById(adminOrgId);
        if (organization == null) {
            throw new ServiceException("审核机构不存在或已失效");
        }
        Admin admin = adminDao.getByAccountId(accountId);
        if (admin == null) {
            throw new ServiceException("审核管理员不存在或已失效");
        }
        // 查询当前最大年份的 参评信息
        ReferenceEntity referenceEntity = referenceDao.selectByApplicantId(applicantId, DateUtil.format(new Date(), "yyyy"));
        if(RegisterStatusEnum.PROVINCE_TITLE.getCode().equals(referenceEntity.getRegisterStatus())){
            throw new ServiceException("已经授予的文明号不能驳回！");
        }
        if( referenceEntity.getIsPost().equals(TrueOrFalseEnum.TRUE.getType())){
            if(role.equals(RoleEnum.LOWER_ADMIN.getCode()) || role.equals(RoleEnum.SECOND_ADMIN.getCode())){
                throw new ServiceException("已经报送的文明号不能驳回！");
            }
        }
        ReferenceReviewLogEntity log = new ReferenceReviewLogEntity();
        log.setReferenceId(referenceEntity.getId());
        log.setReviewAdminId(admin.getId());
        log.setApplicantId(applicantId);
        log.setAction("不通过");
        log.setCause(cause);
        log.setReviewType(RegisterStatusEnum.PROVINCE.getCode());
        referenceReviewLogService.save(log);

        // 报送状态被驳回
        referenceEntity.setRegisterStatus(RegisterStatusEnum.PROVINCE.getCode());
        referenceEntity.setIsPost(TrueOrFalseEnum.FALSE.getType());
        referenceEntity.setOrgPass(TrueOrFalseEnum.FALSE.getType());
        referenceEntity.setBusiPass(TrueOrFalseEnum.FALSE.getType());
        referenceEntity.setIsTop(TrueOrFalseEnum.FALSE.getType());
        referenceEntity.setIsApply(TrueOrFalseEnum.FALSE.getType());
        referenceEntity.setReviewStatus(ReviewedStatusEnum.REJECTED.getCode());
        updateById(referenceEntity);

        // 更新集体表
        applicant.setRegisterStatus(RegisterStatusEnum.PROVINCE.getCode());
        applicantService.updateById(applicant);
        // 更新名额表
        referencePlacesService.reducePlace(applicant, referenceEntity);
    }

    @Override
    public void save(ReferenceInOrUpParam referenceInOrUpParam) {

        ReferenceEntity currentYearReferenceEntity = getCurrentYearReferenceEntity();
        // 修改校验
        if(currentYearReferenceEntity != null){
            if(RegisterStatusEnum.PROVINCE.getCode().equals(currentYearReferenceEntity.getRegisterStatus())){
                throw new ServiceException("当前状态需在创建参评时不允许修改！");    
            }
        }
        if(currentYearReferenceEntity == null){
            insert(referenceInOrUpParam);
        }else{
            referenceInOrUpParam.setId(currentYearReferenceEntity.getId());
            update(referenceInOrUpParam);
        }

    }

    @Override
    public void updateOrg(Long accountId, Integer reviewType, Long joinReviewOrgId) {

        if(reviewType == null){
            throw new ServiceException("参数异常！");
        }
        ReferenceEntity currentYearReferenceEntity = getCurrentYearReferenceEntity();
        if(currentYearReferenceEntity == null){
            throw new ServiceException("未查询到今年参评信息！");
        }
        // 更新参评信息
        if(Integer.valueOf(RegisterStatusEnum.PROVINCE_TITLE.getCode())
                .equals(currentYearReferenceEntity.getRegisterStatus())){
            throw new ServiceException("当年已经授予 不得再次申请！");
        }
        Applicant applicant = applicantService.getEntityByAccountId(accountId);
        if(currentYearReferenceEntity.getIsApply().equals(TrueOrFalseEnum.TRUE.getType())){
            throw new ServiceException("当前参评已经申请 请勿重复申请！");
        }
        currentYearReferenceEntity.setIsApply(TrueOrFalseEnum.TRUE.getType());
        currentYearReferenceEntity.setOrgId(applicant.getOrgId());
        currentYearReferenceEntity.setOrgPath(applicant.getOrgPath());
        currentYearReferenceEntity.setReviewType(reviewType);
        if(Integer.valueOf(OrgTypeEnum.INDUSTRY.getCode()).equals(reviewType)){
            Organization joinReviewOrg = organizationService.getById(joinReviewOrgId);
            currentYearReferenceEntity.setJoinReviewOrgId(joinReviewOrgId);
            currentYearReferenceEntity.setJoinReviewOrgPath(joinReviewOrg.getOrgPath());
        }
        currentYearReferenceEntity.setApplyTime(new Date());
        currentYearReferenceEntity.setReviewStatus(ReviewedStatusEnum.REVIEWING.getCode());
        currentYearReferenceEntity.setRegisterStatus(RegisterStatusEnum.PROVINCE_REVIEW.getCode());
        updateById(currentYearReferenceEntity);

        // 更改关联集体状态
        applicant.setRegisterStatus(RegisterStatusEnum.PROVINCE_REVIEW.getCode());
        applicantService.updateById(applicant);

    }

    @Override
    public List<ReferenceEntity> selectByRegisterStatus(RegisterStatusEnum provinceReview) {

        List<ReferenceEntity> referenceEntities = referenceDao.selectByRegisterStatus(provinceReview);
        return referenceEntities;
    }

    @Override
    public Integer getAwardCount(String orgPath, String vintage) {

        QueryWrapper<ReferenceEntity> referenceEntityQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ReferenceEntity> lambdaQueryWrapper = referenceEntityQueryWrapper.lambda().eq(ReferenceEntity::getIsConfer, TrueOrFalseEnum.TRUE.getType())
                .eq(ReferenceEntity::getVintage, DateUtil.format(new Date(), "yyyy"));
        if(StrUtil.isNotEmpty(orgPath)){
            lambdaQueryWrapper.likeRight(ReferenceEntity::getOrgPath, orgPath);
        }
        return count(referenceEntityQueryWrapper);
    }


    @Override
    public ReferenceEntity getByAppIdAndVintage(Long applicantId, String vintage) {

        return referenceDao.getByAppIdAndVintage(applicantId, vintage);
    }

    @Override
    public ReferenceDetailVO detail(ReferenceEntity referenceEntity) {

        ReferenceDetailVO referenceDetailVO = getReferenceDetailVO(referenceEntity);
        return referenceDetailVO;
    }

    @Override
    public List<ReferenceEntity> selectByRegisterStatusAndPost(RegisterStatusEnum provinceReview, Integer isPost) {

        List<ReferenceEntity> referenceEntities = referenceDao.selectByRegisterStatusAndPost(provinceReview, isPost);
        return referenceEntities;
    }

    @Override
    public Integer getReportedCount(String orgPath, String vintage) {

        QueryWrapper<ReferenceEntity> referenceEntityQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ReferenceEntity> yyyy = referenceEntityQueryWrapper.lambda().eq(ReferenceEntity::getIsPost, TrueOrFalseEnum.TRUE.getType())
                .eq(ReferenceEntity::getVintage, DateUtil.format(new Date(), "yyyy"));

        if(StrUtil.isNotEmpty(orgPath)){
            yyyy.likeRight(ReferenceEntity::getOrgPath, orgPath);
        }
        return count(referenceEntityQueryWrapper);
    }


}